﻿using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Net;
using Sustainalytics.Utils;
using Sustainalytics.Utils.WebApi.ErrorCodes;
using System.Web.Http;
using System.Net.Http;
using Sustainalytics.DataLayer.PI;
using Sustainalytics.ProductInvolvement.BL;
using Sustainalytics.DataLayer;
using Sustainalytics.Claims;
using Sustainalytics.Auth.Claims;
using System.IO;
using System.Net.Http.Headers;
using Sustainalytics.ProductInvolvement.Service.Models;
using System.Text;
using System.Globalization;
using System.Web.Http.Cors;
using System.Linq;
using Sustainalytics.Entities.ProductInvolvement;

namespace Sustainalytics.ProductInvolvement.Service.Controllers
{
    [EnableCors(origins: "*", headers: "*", methods: "*")]
    //[AutoInvalidateCacheOutput]
    [RoutePrefix("api/v1/companyassessments")]
    [LogControllerFilter(true, true, false)]
    public class ProductInvolvementDataController : ApiController, IProductInvolvementDataController
    {
        private readonly IProductInvolvementDataRepository _caRepository;
        private readonly IProductInvolvementBussinesLogic _blLayer;
        private readonly ProductInvolvementPDFReportLogicWithTables _pdfLayer;
        private readonly ProductInvolvementSerilog _log;
        private readonly string _routeKey;
        private readonly IEnumerable<string> _piIndicatorsSymbols;
        private readonly IEnumerable<ProductInvolvementFramework> _piIndicators;
        static IClaimsChecker _claimsChecker;

        public ProductInvolvementDataController(IProductInvolvementDataRepository caRepository, IProductInvolvementBussinesLogic blLayer, ProductInvolvementSerilog log, 
            IClaimsChecker claimsChecker, ProductInvolvementPDFReportLogicWithTables pdfLayer)
        {
            try
            {
                _log = log;
                _caRepository = caRepository;
                _blLayer = blLayer;
                _claimsChecker = claimsChecker;
                _pdfLayer = pdfLayer;
                _routeKey = "pi";
                _piIndicators = caRepository.GetFrameworks();
                _piIndicatorsSymbols = caRepository.GetPiIndicators();
            }
            catch (Exception ex)
            {
                _log.Exception(ex);
                throw;
            }
        }

        [Route("{companyId}/{hasActiveInvolvements?}")]
        public HttpResponseMessage Get(Guid companyId, bool hasActiveInvolvements = false)
        {
            HttpResponseMessage response;
            try
            {

                //claims for Company Assessment online report and at least one PI indicator claim
                if (!_claimsChecker.ValidateCompanyPI(this,_piIndicatorsSymbols, _routeKey))
                {
                    return Request.CreateResponse(HttpStatusCode.Unauthorized);
                }
                
                List<int> userUniverseIds = ClaimsPrincipal.Current.Claims.GetUniverseIds(AccountFeature.ProductInvolvement);
                List<string> claimedIndicators = _claimsChecker.GetClaimedCompanyIndicators(this, _piIndicatorsSymbols, _routeKey);

                IEnumerable<ProductInvolvementFramework> piIndicators = _blLayer.ReadPIIndicators();

                ProductInvolvementData companyAssessment = _blLayer.ReadCompanyAssessment(userUniverseIds, claimedIndicators, companyId);
                
                if (companyAssessment != null)
                {
                    ProductInvolvementDataDto result = ProductInvolvementDataDto.FromCompanyAssessment(companyAssessment, piIndicators, claimedIndicators);

                    if (hasActiveInvolvements)
                    {
                        return GetHasActive(piIndicators, result, claimedIndicators);
                    } else
                    { 
                        response = Request.CreateResponse(HttpStatusCode.OK, result);
                    }
                }
                else
                {
                    response = Request.CreateResponse(HttpStatusCode.NotFound);
                }
            }           
            catch (PICompanyAssessmentNotFoundException_NotResearched)
            {
                return Request.CreateResponse(HttpStatusCode.Accepted, new { message = "Research not available."
                });
            }
            catch (PICompanyAssessmentNotFoundException_ResearchedWithNoData)
            {
                return Request.CreateResponse(HttpStatusCode.Accepted, new { message = "Company has been analyzed by the Product Involvement team, but does not have any Product Involvement indicators, because no issues have been found so far."
                });
            }
            catch (PICompanyAssessmentNotInUniversesException)
            {
                return Request.CreateResponse(HttpStatusCode.Accepted, new { message = "Research available with additional subscription."
                });
            }
            catch (PICompanyAssessmentNotFoundException_FrameworkNotApplicable)
            {
                return Request.CreateResponse(HttpStatusCode.Accepted, new
                {
                    message = "Framework not applicable."
                });
            }            
            catch (Exception ex)
            {
                _log.Exception(ex);
                response = Request.CreateResponse(HttpStatusCode.InternalServerError, new { ErrorStatusCode = WebAPIGeneralErrorCodes.UnhandledException });
            }
            return response;
        }


        //api/v1/companyassessments/export
        [Route("export")]        
        public HttpResponseMessage Post([FromBody] string exportDetailsJsonString)
        {
            HttpResponseMessage response;
            try
            {

                if (exportDetailsJsonString == null)
                {
                    return this.Request.CreateResponse(HttpStatusCode.BadRequest, new { ErrorStatusCode = 5012 });
                }

                //claims for Company Assessment online report
                if (!_claimsChecker.ValidateCompanyPI(this, _piIndicatorsSymbols, _routeKey))
                {
                    return this.Request.CreateResponse(HttpStatusCode.Unauthorized);
                }


                List<int> userUniverseIds = ClaimsPrincipal.Current.Claims.GetUniverseIds(AccountFeature.ProductInvolvement);
                List<string> claimedIndicators = _claimsChecker.GetClaimedCompanyIndicators(this, _piIndicatorsSymbols, _routeKey);

                ProductInvolvementExportDto _exp = Newtonsoft.Json.JsonConvert.DeserializeObject<ProductInvolvementExportDto>(exportDetailsJsonString);

                Guid companyId = Guid.Parse(_exp.CompanyId);
                var corpData = _blLayer.GetCorporateDataByCompanyId(companyId);

                var companyAssessment = _blLayer.ReadCompanyAssessment(userUniverseIds, claimedIndicators, companyId);
                var piIndicators = _blLayer.ReadPIIndicators();

                if (companyAssessment != null)
                {
                
                    var file_result = _pdfLayer.Generate_PI_PDF_Report(companyAssessment, piIndicators, claimedIndicators);

                    response = Request.CreateResponse(HttpStatusCode.OK);

                    response.Content = new PushStreamContent((outStream, httpContent, context) =>
                    {
                        using (Stream stream = new MemoryStream(file_result))
                        {
                            stream.CopyTo(outStream);
                        }
                        outStream.Close();
                    });

                    string filename = "Product_Involvement_" + companyAssessment.CompanyNameSafeUrl + "_" + DateTime.Now.ToString("ddMMyyyy") + ".pdf";
                    filename = RemoveDiacritics(filename);

                    response.Content.Headers.Add("Content-Disposition", "attachement; filename=\"" + filename + "\"");
                    response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
                    return response;
                }
                else
                {
                    response = Request.CreateResponse(HttpStatusCode.NotFound);
                }
            }
            catch (PICompanyAssessmentNotFoundException_NotResearched)
            {
                return Request.CreateResponse(HttpStatusCode.NotFound, new { errCode = "PICompanyAssessmentNotFoundException_NotResearched", message = "The company does not have any data because it doesn't belong to the Product Involvement team research universe." });
            }
            catch (PICompanyAssessmentNotFoundException_ResearchedWithNoData)
            {
                return Request.CreateResponse(HttpStatusCode.NotFound, new { errCode = "PICompanyAssessmentNotFoundException_ResearchedWithNoData", message = "Company has been analyzed by the Product Involvement team, but does not have any Product Involvement indicators, because no issues have been found so far." });
            }
            catch (PICompanyAssessmentNotInUniversesException)
            {
                return Request.CreateResponse(HttpStatusCode.NotFound, new { errCode = "PICompanyAssessmentNotInUniversesException", message = "Research available with additional subscription." });
            }
            catch (Exception ex)
            {
                _log.Exception(ex);
                response = Request.CreateResponse(HttpStatusCode.InternalServerError, new { ErrorStatusCode = WebAPIGeneralErrorCodes.UnhandledException });
            }

            return response;
        }

        private static string RemoveDiacritics(string stIn)
        {
            string stFormD = stIn.Normalize(NormalizationForm.FormD);
            StringBuilder sb = new StringBuilder();

            for (int ich = 0; ich < stFormD.Length; ich++)
            {
                UnicodeCategory uc = CharUnicodeInfo.GetUnicodeCategory(stFormD[ich]);
                if (uc != UnicodeCategory.NonSpacingMark)
                {
                    sb.Append(stFormD[ich]);
                }
            }

            return (sb.ToString().Normalize(NormalizationForm.FormC));
        }


        //gets PI indicators
        //api/v1/company_assessment_details
        [Route("")]
       // [CacheOutput(ServerTimeSpan = 100, ClientTimeSpan = 0, NoCache = true, MustRevalidate = true, Private = true)]
        public HttpResponseMessage Get(bool getIndustries = false, bool getIndicators = false)
        {
            HttpResponseMessage response = new HttpResponseMessage();
            try
            {
                if (getIndicators)
                {
                    var claimedIndicators = _claimsChecker.GetClaimedCompanyIndicators(this, _piIndicatorsSymbols, _routeKey);

                    response = Request.CreateResponse(HttpStatusCode.OK, _piIndicators.Select(x => new
                    {
                        x.Id,
                        x.Name,
                        x.Symbol,
                        x.Categories,
                        HasAccess = claimedIndicators.Contains(x.Symbol)
                    }).OrderBy(x=>x.Name));
                }
                else if (getIndustries)
                {
                    var idustries = _caRepository.GetIndustriesFromCorporateData();
                    response = Request.CreateResponse(HttpStatusCode.OK, idustries);
                }
            }
            catch (Exception ex)
            {
                response = Request.CreateResponse(HttpStatusCode.InternalServerError, new { ErrorStatusCode = WebAPIGeneralErrorCodes.UnhandledException });
            }
            return response;
        }

        private HttpResponseMessage GetHasActive(IEnumerable<ProductInvolvementFramework> piIndicators, ProductInvolvementDataDto companyInvolvement, List<string> claimedIndicators)
        {
                var assessments = piIndicators.Select(x => new
                {
                    x.Symbol,
                    HasAccess = claimedIndicators.Contains(x.Symbol)
                });
            
                foreach (var assessment in assessments)
                {
                    if (assessment.HasAccess && companyInvolvement.Indicators.Any(indicator => assessment.Symbol == indicator.Symbol))
                    {
                        return Request.CreateResponse(HttpStatusCode.OK, new { hasActive = true });
                    }
                }

            return Request.CreateResponse(HttpStatusCode.OK, new { hasActive = false});
        }

        [Route("")]
        public HttpResponseMessage Get([FromUri] ProductInvolvementDataListFilters filterOptions, [FromUri] ListOptions options, string accountId)
        {
            options = options ?? ListOptions.Default;

            HttpResponseMessage response;

            try
            {

                //claims for multiple Company Assessment online report
                if (!_claimsChecker.ValidateMultiCompanyPI(this, _piIndicatorsSymbols, _routeKey))
                    {
                        return this.Request.CreateResponse(HttpStatusCode.Unauthorized);
                    }

                List<int> userUniverseIds = ClaimsPrincipal.Current.Claims.GetUniverseIds(AccountFeature.ProductInvolvement);
                List<string> claimedIndicators = _claimsChecker.GetClaimedCompanyIndicators(this, _piIndicatorsSymbols, _routeKey);

                if (options.GetCount)
                {
                    var count = _blLayer.ReadCompanyAssessmentShortReportCount(filterOptions, userUniverseIds, claimedIndicators);
                    response = Request.CreateResponse(HttpStatusCode.OK, count);
                }
                else
                {
                    var piCompaniesShortReportList = _blLayer.ReadCompanyAssessmentShortReport(
                        filterOptions,
                        userUniverseIds,
                        claimedIndicators,
                        options.Skip,
                        options.Take,
                        options.OrderBy,
                        options.OrderAscending);
                    response = Request.CreateResponse(HttpStatusCode.OK, piCompaniesShortReportList);
                }
            }
            catch (PICompanyAssessmentShortReportEmptyNoUniversesException)
            {
                return Request.CreateResponse(
                    HttpStatusCode.NotFound,
                    new
                    {
                        errCode = "PICompanyAssessmentShortReportEmptyNoUniversesException",
                        message = "No companies, that belong to your Product Involvement universe, available."
                    }
                    );
            }
            catch (PICompanyAssessmentShortReportEmptyNoClaimsException)
            {
                return Request.CreateResponse(
                    HttpStatusCode.NotFound,
                    new
                    {
                        errCode = "PICompanyAssessmentShortReportEmptyNoClaimsException",
                        message = "No companies, that you have Product Involvement indicator claims for, available."
                    }
                    );
            }
            catch (Exception ex)
            {
                _log.Exception(ex);
                response = Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
            }
            return response;
        }

        ////gets additional ownership values from database
        //[Route("ownershipvalues")]
        //public HttpResponseMessage Get()
        //{
        //    HttpResponseMessage response;
        //    try
        //    {
        //        var ownershipValues = _blLayer.ReadOwnershipValues().ToList().OrderBy(x => x);
        //        response = Request.CreateResponse(HttpStatusCode.OK, ownershipValues);
        //    }
        //    catch (Exception ex)
        //    {
        //        _log.Exception(ex);
        //        response = Request.CreateResponse(HttpStatusCode.InternalServerError, new { ErrorStatusCode = WebAPIGeneralErrorCodes.UnhandledException });
        //    }

        //    return response;
        //}
    }
}
